// Copyright 2019 The rhyme_lph Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// S [author] rhyme_lph
// s [email]  rhymelph@gmail.com
// C [github] https://github.com/rhymelph

import 'package:base_plugin/base_plugin.dart';
import 'package:finance_app/generated/l10n.dart';
import 'package:finance_app/src/common/config.dart';
import 'package:finance_app/src/entities/address_entity.dart';
import 'package:finance_app/src/entities/company_financial_year_entity.dart';
import 'package:finance_app/src/entities/ocr_attachment_entity.dart';
import 'package:finance_app/src/entities/payment_term_entity.dart';
import 'package:finance_app/src/entities/setting_alerts_entity.dart';
import 'package:finance_app/src/entities/setting_app_entity.dart';
import 'package:finance_app/src/entities/setting_data_entity.dart';
import 'package:finance_app/src/entities/setting_info_entity.dart';
import 'package:finance_app/src/http_service/http_coa_service.dart';
import 'package:finance_app/src/http_service/http_common_service.dart';
import 'package:finance_app/src/http_service/http_company_service.dart';
import 'package:finance_app/src/http_service/http_setting_service.dart';
import 'package:finance_app/src/mixin/single_attach_mixin.dart';
import 'package:finance_app/src/provider/dashboard/dashboard_view_provider.dart';
import 'package:finance_app/src/provider/dashboard_provider.dart';
import 'package:finance_app/src/router_gen/override_route_providers.dart';
import 'package:finance_app/src/router_gen/router_gen_providers.dart';
import 'package:finance_app/src/utils/date_time_utils.dart';
import 'package:finance_app/src/widgets/bottom_sheet/address_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/currency_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/date_time_select_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/delete_info_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/got_it_info_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/got_it_tip_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/list_select_bottom_sheet.dart';
import 'package:flutter/material.dart';
import 'package:finance_app/src/page/setting/company_profile_page.dart';

class CompanyProfileProvider extends BaseProvider with SingleAttachMixin {
  SettingAppBusinessType businessType;

  DateTime startDate;
  DateTime endDate;

  SettingAppIndustryType industry;

  var imagePath;

  TextEditingController businessNameController = TextEditingController();
  FocusNode businessNameFocusNode = FocusNode();

  @override
  Future get dataFuture => null;

  TextEditingController uenController = TextEditingController();
  FocusNode uenFocusNode = FocusNode();
  TextEditingController emailController = TextEditingController();
  FocusNode emailFocusNode = FocusNode();
  TextEditingController nextMonthController = TextEditingController();
  FocusNode nextMonthFocusNode = FocusNode();

  TextEditingController websiteController = TextEditingController();
  FocusNode websiteFocusNode = FocusNode();
  TextEditingController phoneNumberController = TextEditingController();
  FocusNode phoneNumberFocusNode = FocusNode();
  String countryCode = '+65';
  String address;
  TextEditingController unitNumberController = TextEditingController();
  FocusNode unitNumberFocusNode = FocusNode();
  TextEditingController postalCodeController = TextEditingController();
  FocusNode postalCodeFocusNode = FocusNode();
  String deliveryAddress;

  TextEditingController deliverUnitNumberController = TextEditingController();
  FocusNode deliverUnitNumberFocusNode = FocusNode();
  TextEditingController deliverPostalCodeController = TextEditingController();
  FocusNode deliverPostalCodeFocusNode = FocusNode();

  List<CompanyFinancialYearEntity> financialYears = [];

  int id;

  @override
  void initState() {
    super.initState();
    _loadSettingInfo();
    _getFinancialYears();
  }

  void initDate(CompanyEntity data) {
    networkPath = data.logo;
    id = data.id;
    uenController.text = data.uen;
    emailController.text = data.email;
    websiteController.text = data.website;
    // phoneNumberController.text =
    // countryCode
    address = data.addressLine1;
    // unitNumberController.text = data.
    postalCodeController.text = data.addressPostalCode;
    // deliveryAddressController.text =data.
    // deliverUnitNumberController.text = data.uni
    deliverPostalCodeController.text = data.addressPostalCode;
    businessType = Config.settingApp.businessType.firstWhere(
        (element) => element.key == data.businessType,
        orElse: () => null);
    industry = Config.settingApp.industryType.firstWhere(
        (element) => element.key == data.industryType,
        orElse: () => null);
    businessNameController.text = data.name;
    nextMonthController.text = data.financialYearPeriod?.toString() ?? '';
    startDate =
        DateTimeUtils.toDateTime(data.financialYearStartAt, 'yyyy-MM-dd');
    endDate = DateTimeUtils.toDateTime(data.financialYearEndAt, 'yyyy-MM-dd');
    DateTime time = DateTime.now();
    if (startDate == null) {
      startDate = DateTime(time.year, 1, 1);
    }
    if (endDate == null) {
      endDate = DateTime(time.year, 12, 31);
    }
    if (nextMonthController.text.isEmpty) {
      nextMonthController.text = '12';
    }
    phoneNumberController.text = data.phoneNumber;
    countryCode = data.countryCode;
    if (countryCode == null) {
      countryCode = '+65';
    }
    unitNumberController.text = data.addressUnit;
    if (data.deliveryAddressLine1 != null ||
        data.deliveryAddressUnit != null ||
        data.deliveryAddressPostalCode != null) {
      isShowDeliveryAddress = true;
    }
    deliveryAddress = data.deliveryAddressLine1;
    deliverUnitNumberController.text = data.deliveryAddressUnit;
  }

  void unFocus() {
    obtainContext?.call((context) {
      FocusScope.of(context).requestFocus(FocusNode());
    });
  }

  void updateCountryCode(value) {
    countryCode = value;
    update();
  }

  bool isShowDeliveryAddress = false;

  void onAddDeliveryAddress() {
    isShowDeliveryAddress = !isShowDeliveryAddress;
    update();
  }

  void onChangeBusinessType() {
    obtainContext?.call((context) async {
      final result =
          await showBusinessTypeSelectBottomSheet(context, businessType);
      if (result != null) {
        businessType = result;
        update();
      }
    });
  }

  void onChangeStartDate() {
    unFocus();
    obtainContext?.call((context) async {
      DateTime result = await showDateTimeSelectBottomSheet(
          context, S.current.financial_year_start_date, startDate,
          withinFinancialYear: false);
      if (result != null) {
        startDate = result;
        update();
      }
    });
  }

  void onChangeEndDate() {
    unFocus();
    obtainContext?.call((context) async {
      DateTime result = await showDateTimeSelectBottomSheet(
          context, S.current.financial_year_end_date, endDate,
          withinFinancialYear: false);
      if (result != null) {
        endDate = result;
        update();
      }
    });
  }

  void onChangeFinancialYear() {
    obtainContext?.call((context) async {
      CompanyFinancialYearEntity selected = financialYears.firstWhere(
          (element) => element.status == 1,
          orElse: () => financialYears.last);
      CompanyFinancialYearEntity result =
          await showFinancialYearSelectBottomSheet(
              context, selected, financialYears.reversed.toList());
      if (result != selected) {
        bool isSuccess = await showSwitchFinancialYearConfirmationBottomSheet(
          context,
          DateTimeUtils.formatFinancialYearDate(
              result.startDate, result.endDate),
        );
        if (isSuccess != null && isSuccess) {
          bool isSwitchSuccess = false;
          await post(HttpCompanyService.selectFinancialYear(result.id),
              autoHandler: AutoHandler.Toast,
              loadingTip: imagePath != null ? null : S.current.loading,
              onSuccess: (result) {
            isSwitchSuccess = true;
          });
          if (isSwitchSuccess) {
            await _getFinancialYears();
            await _loadCompanyData();
            await _loadCOA();
            await showSwitchFinancialYearSuccessTipBottomSheet(
                context,
                DateTimeUtils.formatFinancialYearDate(
                    result.startDate, result.endDate));

            Routes.navigateTo(RouterGenProviders.dashboardPage,
                clearStack: true);
          }
        }
      }
    });
  }

  void onShowInfo() {
    unFocus();
    obtainContext?.call((context) {
      showSwitchFinancialYearInfoBottomSheet(context);
    });
  }

  void onChangeIndustry() async {
    final result = await Routes.navigateTo(
        RouterGenProviders.industrySelectPage,
        params: {'select': industry});
    if (result != null) {
      industry = result;
      update();
    }
  }

  void onUpdateLoadAvatar() async {
    unFocus();
    if (imagePath != null ||
        networkPath != null &&
            !networkPath.startsWith('data:image/png;base64')) {
      onSelectFile(imagePath,
          onChooseAgain: () {
            obtainContext?.call((context) {
              Navigator.of(context).pop();
            });
            onAddAttachment(
                title: S.current.upload_photo, attachName: S.current.upload);
          },
          againText: S.current.choose_again,
          onRemove: () {
            obtainContext?.call((context) {
              Navigator.of(context).pop();
            });
            imagePath = null;
            networkPath = null;
            update();
          },
          canDelete: false,
          attachments: (networkPath?.isNotEmpty ?? false)
              ? (OcrAttachmentEntity()..url = networkPath)
              : null);
    } else {
      onAddAttachment(
          title: S.current.upload_photo, attachName: S.current.upload);
    }
  }

  void onSave() async {
    unFocus();
    String avatarUrl = networkPath;

    if (imagePath != null) {
      final result = await uploadFiles(true);
      if (result != null) {
        avatarUrl = result.url;
      }
    }
    CompanyEntity companyEntity;

    int nextMonth;
    try {
      nextMonth = int.parse(nextMonthController.text);
    } catch (e) {}
    await post(
        HttpCompanyService.updateCompanies(
          id,
          name: businessNameController.text,
          business_type: businessType?.key,
          industry_type: industry?.key,
          uen: uenController.text,
          phone_number: phoneNumberController.text,
          email: emailController.text,
          website: websiteController.text,
          logo: avatarUrl ?? '',
          // country: ,
          //   address_country:
          //   address_city:
          address_postal_code: postalCodeController.text,
          address_line_1: address,
          // address_line_2: ,
          address_unit: unitNumberController.text,
          // delivery_address_country: ,
          // delivery_address_city: ,
          delivery_address_postal_code: deliverPostalCodeController.text,
          delivery_address_line_1: deliveryAddress,
          // delivery_address_line_2: ,
          delivery_address_unit: deliverUnitNumberController.text,
          financial_year_start_at:
              DateTimeUtils.formatDateTime(startDate, 'yyyy-MM-dd'),
          financial_year_end_at:
              DateTimeUtils.formatDateTime(endDate, 'yyyy-MM-dd'),
          financial_year_period: nextMonth,
          // enable_gst:
          // gst_number:
          // gst_effective_date:
        ),
        autoHandler: AutoHandler.Toast,
        loadingTip: imagePath != null ? null : S.current.loading,
        onSuccess: (result) {
      companyEntity = getEntityFromResult<CompanyEntity>(result);
    });
    if (imagePath != null) {
      obtainContext?.call((context) {
        Navigator.of(context).pop();
      });
    }
    if (companyEntity != null) {
      await _getFinancialYears();
      imagePath = null;
      networkPath = companyEntity.logo;
      if (companyEntity.id == Config.currentCompany.id) {
        RProvider.myProvider.globalMap[ConfigKey.currentCompany] =
            companyEntity;
        await RProvider.myProvider.updateGlobalMap();
      }
      DashboardProvider dashboard = Config.dashboardProvider;
      await dashboard?.loadAvailableCompany();
      dashboard.update();

      update();
      obtainContext?.call((context) {
        showInformationUpdateSuccessTipBottomSheet(context);
      });
    }
  }

  void onChangeAddress() {
    obtainContext?.call((context) async {
      AddressEntity entity = await showAddressBottomSheet(context, null,
          (String searchData) async {
        List<AddressEntity> addressList;
        await post(HttpCommonService.searchAddress(searchData),
            autoHandler: AutoHandler.Toast, onSuccess: (result) {
          addressList = getEntityFromResult<List<AddressEntity>>(result);
        });
        if (addressList == null) {
          addressList = [];
        }
        return addressList;
      });
      if (entity != null) {
        address = entity.address;
        postalCodeController.text = entity.code;
        update();
      }
    });
  }

  void onChangeDeliveryAddress() {
    obtainContext?.call((context) async {
      AddressEntity entity = await showAddressBottomSheet(context, null,
          (String searchData) async {
        List<AddressEntity> addressList;
        await post(HttpCommonService.searchAddress(searchData),
            autoHandler: AutoHandler.Toast, onSuccess: (result) {
          addressList = getEntityFromResult<List<AddressEntity>>(result);
        });
        if (addressList == null) {
          addressList = [];
        }
        return addressList;
      });
      if (entity != null) {
        deliveryAddress = entity.address;
        deliverPostalCodeController.text = entity.code;
        update();
      }
    });
  }

  void onNumberFormat() {
    Routes.navigateTo(RouterGenProviders.numberFormatPage);
  }

  void onTemplateStyle() {
    Routes.navigateTo(RouterGenProviders.templateStylePage);
  }

  void onUnitOfMeasurement() {
    Routes.navigateTo(RouterGenProviders.unitOfMeasurementPage);
  }

  void onChangeCurrency() {
    obtainContext?.call((context) async {
      final result = await showCurrencyBottomSheet(
          context, Config.settingInfo.currencyCode);
      if (result != null && result != Config.settingInfo) {
        SettingDataCurrency currency = result;
        await post(
            HttpSettingService.updateSettingInfo(
              default_currency_code: currency.key,
            ),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) async {
          Config.settingInfo.defaultCurrencyCode = currency.key;
          await RProvider.myProvider.updateGlobalMap();
        });
        Config.dashboardProvider
            ?.getChildProvider<DashboardViewProvider>()
            ?.loadData();
      }
    });
  }

  void onChangePaymentType() {
    obtainContext?.call((context) async {
      final result = await showPaymentMethodBottomSheet(
          context, Config.settingInfo.paymentType);
      if (result != null && result != Config.settingInfo.paymentType) {
        SettingDataPaymentType paymentType = result;
        await post(
            HttpSettingService.updateSettingInfo(
              default_payment_type_id: paymentType.id,
            ),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) async {
          Config.settingInfo.defaultPaymentTypeId = paymentType.id;
          await RProvider.myProvider.updateGlobalMap();
        });
      }
    });
  }

  void onChangePaymentTerm() {
    obtainContext?.call((context) async {
      final result =
          await showPaymentTermBottomSheet(context, Config.paymentTerm);
      if (result != null && result != Config.paymentTerm) {
        PaymentTermEntity paymentTerm = result;
        await post(
            HttpSettingService.updateSettingInfo(
              default_payment_term_id: paymentTerm.id,
            ),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) async {
          Config.settingInfo.defaultPaymentTermId = paymentTerm.id;
          await RProvider.myProvider.updateGlobalMap();
        });
      }
    });
  }

  void onChangeTaxType() async {
    obtainContext?.call((context) async {
      final result =
          await showGstRateBottomSheet(context, Config.settingInfo.taxData);
      if (result != null && result != Config.settingInfo.taxData) {
        final taxType = result;
        await post(
            HttpSettingService.updateSettingInfo(
              tax_id: taxType.id,
            ),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) async {
          Config.settingInfo.taxId = taxType.id;
          await RProvider.myProvider.updateGlobalMap();
        });
      }
    });
  }

  void onChangeDateFormat() {
    obtainContext?.call((context) async {
      final result = await showDateFormatSelectBottomSheet(
          context, Config.settingInfo.dateFormat);
      if (result != null && result != Config.settingInfo.dateFormat) {
        final settingInfo = Config.settingInfo..dateFormat = result;
        await post(
            HttpSettingService.updateSettingInfo(
              date_format: settingInfo.dateFormat,
            ),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) async {
          RProvider.myProvider.globalMap[ConfigKey.settingInfo] = settingInfo;
          await RProvider.myProvider.updateGlobalMap();
          update();
        });
      }
    });
  }

  void onCheckAlertSetting(SettingAlertsEntity e) async {
    List<String> templateAlerts = List.from(Config.settingInfo.alerts);
    if (templateAlerts.contains(e.key)) {
      templateAlerts.remove(e.key);
    } else {
      templateAlerts.add(e.key);
    }
    bool isSuccess = false;
    await post(
        HttpSettingService.updateSettingInfo(
          alerts: templateAlerts,
        ),
        autoHandler: AutoHandler.Toast,
        loadingTip: S.current.loading, onSuccess: (result) {
      isSuccess = true;
    });
    if (isSuccess == true) {
      Config.settingInfo.alerts = templateAlerts;
      await RProvider.myProvider.updateGlobalMap();
    }
  }

  void _loadSettingInfo() {
    post(HttpSettingService.getSettingInfo(), autoHandler: AutoHandler.Toast,
        onSuccess: (result) async {
      RProvider.myProvider.globalMap[ConfigKey.settingInfo] =
          getEntityFromResult<SettingInfoEntity>(result);
      await RProvider.myProvider.updateGlobalMap();
    });
  }

  Future<void> _getFinancialYears() async {
    await post(HttpCompanyService.getFinancialYears(),
        autoHandler: AutoHandler.Toast, onSuccess: (result) async {
      financialYears =
          getEntityFromResult<List<CompanyFinancialYearEntity>>(result);
      RProvider.myProvider.globalMap[ConfigKey.currentFYs] = financialYears;
      await RProvider.myProvider.updateGlobalMap();
      update();
    });
  }

  Future<void> _loadCompanyData() async {
    await post(
        HttpCompanyService.showCompanies(Config.userProfile.defaultCompanyId),
        autoHandler: AutoHandler.Toast,
        loadingTip: S.current.loading, onSuccess: (result) async {
      CompanyEntity entity = getEntityFromResult<CompanyEntity>(result);
      RProvider.myProvider.globalMap[ConfigKey.currentCompany] = entity;
      await RProvider.myProvider.updateGlobalMap();
    });
  }

  Future<void> _loadCOA() async {
    await post(HttpCoaService.coaNewList(),
        autoHandler: AutoHandler.Toast,
        loadingTip: S.current.loading,
        onSuccess: (result) async {});
  }

  void selectFinancialYear(CompanyFinancialYearEntity financialYear) {
    post(HttpCompanyService.selectFinancialYear(financialYear.id),
        autoHandler: AutoHandler.Toast, onSuccess: (result) async {});
  }
}
